package com.carefree.system.common.utils;

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.DeleteObjectsRequest;
import com.aliyun.oss.model.DeleteObjectsResult;
import com.aliyun.oss.model.MatchMode;
import com.aliyun.oss.model.PolicyConditions;
import com.carefree.common.emus.StatusCodeEnum;
import com.carefree.common.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @ClassName:AliyunOssConfig
 * @Description:
 * @Author Tengbin tengbin234@163.com
 */
@Slf4j
@Component
public class AliyunOssUtils {
    @Value("${alicloud.access-key}")
    private String accessKey;

    @Value("${alicloud.secret-key}")
    private String secretKey;

    @Value("${alicloud.oss.endpoint}")
    private String endpoint;

    @Value("${alicloud.oss.bucket}")
    private String bucket;

    /**
     * 默认文件存放路径
     */
    @Value("${alicloud.oss.default-bucket-path}")
    private String defaultBucketPath;

    /**
     * 存储用户头像路径
     */
    @Value("${alicloud.oss.avatar-bucket-path}")
    private String avatarBucketPath;


    /**
     * 服务端签名直传
     *
     * @return
     */
    public Map<String, String> policy() {

        // Bucket 域名
        String host = "https://" + bucket + "." + endpoint;

        // 初始化返回结果
        Map<String, String> respMap = null;

        // 创建ossClient实例
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKey, secretKey);

        try {
            long expireTime = 30;
            long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
            Date expiration = new Date(expireEndTime);

            PolicyConditions policyConditions = new PolicyConditions();
            policyConditions.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
            policyConditions.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, defaultBucketPath);

            String postPolicy = ossClient.generatePostPolicy(expiration, policyConditions);
            byte[] binaryData = postPolicy.getBytes(StandardCharsets.UTF_8);
            String encodedPolicy = BinaryUtil.toBase64String(binaryData);

            String postSignature = ossClient.calculatePostSignature(postPolicy);

            respMap = new LinkedHashMap<>();
            respMap.put("accessid", accessKey);
            respMap.put("policy", encodedPolicy);
            respMap.put("signature", postSignature);
            respMap.put("dir", defaultBucketPath);
            respMap.put("host", host);
            respMap.put("expire", String.valueOf(expireEndTime / 1000));

        } catch (Exception e) {
            log.error("阿里云-服务端签名直传-发生异常，将造成后台管理界面无法上传图片");
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return respMap;
    }

    /**
     * 上传图片
     *
     * @param multipartFile
     * @return
     */
    public String uploadImages(MultipartFile multipartFile) {
        if (multipartFile.isEmpty()) {
            throw new BusinessException(StatusCodeEnum.DATA_ERROR);
        }
        // oss存储路径
        String returnUrl = "";
        // 创建OSS实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKey, secretKey);

        try {
            //获取上传文件输入流
            InputStream inputStream = multipartFile.getInputStream();
            //获取文件名称
            String fileName = multipartFile.getOriginalFilename();
            // 获取文件的后缀名
            String suffixName = fileName.substring(fileName.lastIndexOf("."));
            // 拼装完成后的文件名
            fileName = avatarBucketPath + System.currentTimeMillis() + suffixName;

            //调用oss方法实现上传:
            // 第一个参数  Bucket名称
            // 第二个参数  上传到oss文件路径和文件名称   aa/bb/1.jpg
            // 第三个参数  上传文件输入流
            ossClient.putObject(bucket, fileName, inputStream);
            // 关闭OSSClient。
            ossClient.shutdown();
            //把上传之后文件路径返回
            //需要把上传到阿里云oss路径手动拼接出来
            returnUrl = "https://" + bucket + "." + endpoint + "/" + fileName;
        } catch (IOException e) {
            log.error("阿里云-上传用户头像-发生IO异常，图片上传失败！");
            throw new BusinessException(StatusCodeEnum.UPLOAD_IMG_EXCEPTION);
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return returnUrl;
    }


    /**
     * 根据文件名删除文件
     *
     * @param fileName   文件名
     * @param bucketPath 文件存储的路径
     * @return
     */
    public boolean deleteFile(String fileName, String bucketPath) {
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKey, secretKey);

        try {
            String key = StringUtils.hasText(bucketPath) ? bucketPath + fileName : fileName;

            ossClient.deleteObject(bucket, key);

            return true;
        } catch (ClientException ce) {
            log.error("阿里云-根据文件名删除文件-发生客户端异常，文件删除失败！");
            return false;
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    /**
     * 批量删除文件
     *
     * @param fileNames  文件名集合(文件完整路径中不能包含Bucket名称)
     * @param bucketPath 文件存储的路径
     * @return
     */
    public boolean deleteFiles(List<String> fileNames, String bucketPath) {
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKey, secretKey);

        List<String> keys = fileNames.stream().map(fileName -> StringUtils.hasText(bucketPath) ? bucketPath + fileName : fileName).collect(Collectors.toList());

        try {
            DeleteObjectsResult deleteObjectsResult = ossClient.deleteObjects(new DeleteObjectsRequest(bucket).withKeys(keys).withEncodingType("url"));
            List<String> deletedObjects = deleteObjectsResult.getDeletedObjects();
            return ! deletedObjects.isEmpty();
        } catch (Exception e) {
            log.error("阿里云-批量删除文件失败-发生客户端异常！");
            return false;
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }


}
